#ifndef _VECTOR_
#define _VECTOR_

#include <math.h>


struct	Vec3
{
	float	x, y, z;

	Vec3() {}
	Vec3(float x, float y, float z) { this->x = x, this->y = y, this->z = z; }
	Vec3(const float * f) { this->x = f[0]; this->y = f[1]; this->z = f[2]; } 

	Vec3& operator += (const Vec3 & v) { this->x += v.x; this->y += v.y; this->z += v.z; return *this; }
	Vec3& operator -= (const Vec3 & v) { this->x -= v.x; this->y -= v.y; this->z -= v.z; return *this; }
	Vec3& operator *= (float f) { this->x *= f; this->y *= f; this->z *= f; return *this; }
	Vec3& operator /= (float f) { this->x /= f; this->y /= f; this->z /= f; return *this; }
	
	bool operator < (const Vec3 & v) const { return (this->x < v.x && this->y < v.y && this->z < v.z) ? true : false; }
	bool operator > (const Vec3 & v) const { return (this->x > v.x && this->y > v.y && this->z > v.z) ? true : false; }

	Vec3 & Normalize() { float s = 1.0f / sqrt(x*x+y*y+z*z); x *= s; y *= s; z *=s; return *this; }
	Vec3 operator - () const { return Vec3(-x, -y, -z); }

	static Vec3 Lerp(const Vec3& a, const Vec3& b, float w) { return Vec3(a.x+(b.x-a.x)*w, a.y+(b.y-a.y)*w, a.z+(b.z-a.z)*w); }
	static float Magnitude(const Vec3 &v) { return sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); }
	static Vec3 Normalize(const Vec3 &v) { float s = 1.0f / sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); return Vec3(v.x*s, v.y*s, v.z*s); }
	static Vec3 CrossProduct(const Vec3 &a, const Vec3 &b) { return Vec3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); }
	static float DotProduct(const Vec3 &a, const Vec3 &b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
	static Vec3 CRSpline(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, float t);
	static Vec3 ZERO;
	static Vec3 XAXIS, YAXIS, ZAXIS;

} ;


inline Vec3 operator * (const Vec3 & v, float s) { return Vec3(v.x*s, v.y*s, v.z*s); }
inline Vec3 operator * (float s, const Vec3 & v) { return Vec3(v.x*s, v.y*s, v.z*s); }
inline Vec3 operator + (const Vec3 & a, const Vec3 & b) { return Vec3(a.x+b.x, a.y+b.y, a.z+b.z); }
inline bool operator == (const Vec3 & v1, const Vec3 & v2) { return v1.x == v2.x && v1.y == v2.y && v1.z == v2.z ? true : false; }
inline bool operator != (const Vec3 & v1, const Vec3 & v2) { return !(operator == (v1, v2)); }

inline Vec3 operator - (const Vec3 & a, const Vec3 & b) { return Vec3(a.x-b.x, a.y-b.y, a.z-b.z); }

struct	Vec4
{
	float x, y, z, w;

	Vec4() {}
	Vec4(float x, float y, float z, float w) { this->x = x, this->y = y, this->z = z; this->w = w; }
	Vec4(const float * f) { this->x = f[0]; this->y = f[1]; this->z = f[2]; this->w = f[3]; } 

	Vec4& operator += (const Vec4 & v) { this->x += v.x; this->y += v.y; this->z += v.z; this->w += v.w; return *this; }
	Vec4& operator -= (const Vec4 & v) { this->x -= v.x; this->y -= v.y; this->z -= v.z; this->w -= v.w; return *this; }
	Vec4& operator *= (float f) { this->x *= f; this->y *= f; this->z *= f; this->w *= f; return *this; }
	Vec4& operator /= (float f) { this->x /= f; this->y /= f; this->z /= f; this->w /= f; return *this; }

	static Vec4 ZERO;
} ;



inline Vec4 operator * (const Vec4 & v, float s) { return Vec4(v.x*s, v.y*s, v.z*s, v.w*s); }

struct	Vec2
{
	float x, y;

	Vec2() {}
	Vec2(float x, float y) { this->x = x; this->y = y; }
	Vec2(const float * f) { this->x = f[0]; this->y = f[1]; }  
	Vec2(const Vec2& v) { x = v.x; y = v.y; }

	Vec2 operator - () { return Vec2(-x, -y); }

	Vec2& operator += (const Vec2 & v) { this->x += v.x; this->y += v.y; return *this; }
	Vec2& operator -= (const Vec2 & v) { this->x -= v.x; this->y -= v.y; return *this; }
	Vec2& operator *= (float f) { this->x *= f; this->y *= f; return *this; }
	Vec2& operator /= (float f) { this->x /= f; this->y /= f; return *this; }

	static float DotProduct(const Vec2& v1, const Vec2& v2) { return v1.x*v2.x + v1.y*v2.y; }
	static float CrossProduct(const Vec2& v1, const Vec2& v2) { return v1.x*v2.y - v1.y*v2.x; }
	
	static Vec2 ZERO;
};

inline Vec2 operator - (const Vec2& v1, const Vec2& v2) { return Vec2(v1.x-v2.x, v1.y-v2.y); }
inline Vec2 operator + (const Vec2& v1, const Vec2& v2) { return Vec2(v1.x+v2.x, v1.y+v2.y); }
inline Vec2 operator * (const Vec2& v, float s) { return Vec2(v.x*s, v.y*s); }
inline Vec2 operator * (float s, const Vec2& v) { return Vec2(v.x*s, v.y*s); }


#endif